package com.tanhua.server.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import com.aliyuncs.utils.StringUtils;
import com.tanhua.autoconfig.template.OssTemplate;
import com.tanhua.commons.utils.Constants;
import com.tanhua.dubbo.api.MovementApi;
import com.tanhua.dubbo.api.UserInfoApi;
import com.tanhua.dubbo.api.VisitorsApi;
import com.tanhua.model.domain.UserInfo;
import com.tanhua.model.mongo.Movement;
import com.tanhua.model.mongo.Visitors;
import com.tanhua.model.vo.ErrorResult;
import com.tanhua.model.vo.MovementsVo;
import com.tanhua.model.vo.PageResult;
import com.tanhua.model.vo.VisitorsVo;
import com.tanhua.server.exception.BusinessException;
import com.tanhua.server.interceptor.UserHolder;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class MovementsService {
    @Autowired
    private OssTemplate ossTemplate;

    @DubboReference
    private MovementApi movementApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private MqMessageService mqMessageService;

    /**
     * 发布动态
     *
     * @param movement
     * @param imageContent
     * @throws IOException
     */
    public void publishMovement(Movement movement, MultipartFile[] imageContent) throws IOException {
        //1、判断发布动态的内容是否存在
        if (StringUtils.isEmpty(movement.getTextContent())) {
            //如果为空抛一个异常
            throw new BusinessException(ErrorResult.error());
        }
        //2、获取当前登录的用户id
        Long userId = UserHolder.getUserId();
        //3、将文件内容上传到阿里云OSS，获取请求地址
        List<String> list = new ArrayList<>();
        for (MultipartFile multipartFile : imageContent) {
            String upload = ossTemplate.upload(multipartFile.getOriginalFilename(), multipartFile.getInputStream());
            list.add(upload);
        }
        //4、将数据封装到Movement对象
        movement.setUserId(userId);
        movement.setMedias(list);
        //5、调用API完成发布动态
        String movementId = movementApi.publish(movement);
        //发布动态时调用工具类进行审核
        mqMessageService.sendAudiService(movementId);
        //调用工具类完成日志消息发送
        mqMessageService.sendLogService(movement.getUserId(), "0201", "movement", movementId);
    }

    /**
     * 查看个人动态
     *
     * @param userId
     * @param page
     * @param pagesize
     * @return
     */
    public PageResult all(Long userId, Integer page, Integer pagesize) {
        //1、根据用户id，调用API查询个人动态内容（PageResult  -- Movement）
        PageResult pr = movementApi.all(userId, page, pagesize);
        //2、获取PageResult中的item列表对象
        List<Movement> items = (List<Movement>) pr.getItems();
        //3、非空判断
        if (CollUtil.isEmpty(items)) {
            return pr;
        }
        //4、循环数据列表
        //通过userId获取info对象
        UserInfo userInfo = userInfoApi.findById(userId);
        //创建一个MovementsVo集合
        List<MovementsVo> vos = new ArrayList<>();
        for (Movement item : items) {
            //5、一个Movement构建一个Vo对象
            MovementsVo vo = MovementsVo.init(userInfo, item);
            //添加vo进集合
            vos.add(vo);
        }
        //6、构建返回值
        pr.setItems(vos);
        //浏览动态
        mqMessageService.sendLogService(Long.valueOf(UserHolder.getUserId()), "0202", "movement", userId.toString());
        return pr;
    }

    /**
     * 好友动态查询
     *
     * @param page
     * @param pagesize
     * @return
     */
    public PageResult movements(Integer page, Integer pagesize) {
        //1.获取用户id
        Long userId = UserHolder.getUserId();
        //2.调用api查询数据列表
        List<Movement> list = movementApi.movements(userId, page, pagesize);
        //浏览动态
        mqMessageService.sendLogService(Long.valueOf(UserHolder.getUserId()), "0202", "movement", userId.toString());
        return getPageResult(page, pagesize, list);
    }

    /**
     * 封装的推荐和好友查询的公用方法
     *
     * @param page
     * @param pagesize
     * @param list
     * @return
     */
    private PageResult getPageResult(Integer page, Integer pagesize, List<Movement> list) {
        //3.判断
        if (CollUtil.isEmpty(list)) {
            return new PageResult();
        }
        //4.获取好友用户id
        List<Long> values = CollUtil.getFieldValues(list, "userId", Long.class);
        //5.调用api查询用户详情
        Map<Long, UserInfo> userMaps = userInfoApi.findByIds(values, null);
        //6.循环数据列表
        List<MovementsVo> vos = new ArrayList<>();
        for (Movement movement : list) {
            //7.一个movement构建一个vo对象
            UserInfo userInfo = userMaps.get(movement.getUserId());
            MovementsVo vo = MovementsVo.init(userInfo, movement);
            vos.add(vo);
        }
        //8.构造返回值
        return new PageResult(page, pagesize, 0L, vos);
    }

    /**
     * 推荐动态查询
     *
     * @param page
     * @param pagesize
     * @return
     */
    public PageResult recommend(Integer page, Integer pagesize) {
        //1.从redis中获取当前用户推荐PID列表
        String redisKey = "MOVEMENTS_RECOMMEND_" + UserHolder.getUserId();
        String redisData = this.redisTemplate.opsForValue().get(redisKey);
        //2.判断是否存在
        // Collections.EMPTY_LIST = new 实现类的意思
        List<Movement> list = Collections.EMPTY_LIST;
        if (redisData == null) {
            //3.如果不存在，调用api随机获取十条动态数据
            list = movementApi.random(pagesize);
        } else {
            //4、如果存在，处理pid数据
            // 数据通过,切割 得到一个数组
            String[] split = redisData.split(",");
            //判断当前页的起始条数是否小于数组总数
            if ((page - 1) * pagesize < split.length) {
                //使用stream流进行分页 把String转换为Long类型集合
                List<Long> longs = Arrays.stream(split)
                        .skip((page - 1) * pagesize)
                        .limit(pagesize)
                        .map(e -> Convert.toLong(e))
                        .collect(Collectors.toList());
                //5、调用API根据PID数组查询动态数据
                list = movementApi.findByPids(longs);
            }
        }
        //调用公共方法构造返回
        return getPageResult(page, pagesize, list);
    }

    /**
     * 根据id查询动态
     *
     * @param movementId
     * @return
     */
    public MovementsVo findById(String movementId) {
        //调用service查询
        Movement movement = movementApi.findById(movementId);
        if (movement == null) {
            return null;
        } else {
            //通过movement表中的用户id查询用户的信息 封装vo对象返回
            UserInfo userInfo = userInfoApi.findById(movement.getUserId());
            return MovementsVo.init(userInfo, movement);
        }
    }

    @DubboReference
    private VisitorsApi visitorsApi;

    /**
     * 谁看过我
     *
     * @return
     */
    public List<VisitorsVo> queryVisitorsList() {
        //1、查询访问时间
        String key = Constants.VISITORS_USER;
        String hashKey = String.valueOf(UserHolder.getUserId());
        String value = (String) redisTemplate.opsForHash().get(key, hashKey);
        Long date = StringUtils.isEmpty(value) ? null : Long.valueOf(value);
        //2.调用api查看所有看过我的用户
        List<Visitors> list = visitorsApi.queryVisitorsList(date, UserHolder.getUserId());
        //3.判断是否为空，为空返回一个空的集合
        if (CollUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        //4.获取用户中每一个访问人的id
        List<Long> userIds = CollUtil.getFieldValues(list, "visitorUserId", Long.class);
        //5.调用api获取每一个人的用户详情
        Map<Long, UserInfo> infoMap = userInfoApi.findByIds(userIds, null);
        //6.封装vo返回
        List<VisitorsVo> vos = new ArrayList<>();
        for (Visitors visitors : list) {
            UserInfo userInfo = infoMap.get(visitors.getVisitorUserId());
            if (userInfo != null) {
                VisitorsVo vo = VisitorsVo.init(userInfo, visitors);
                vos.add(vo);
            }
        }
        return vos;
    }
}
